Gas Data
The gas data represents information about various gas stations,
including their location, services offered, population of compromised
individuals (POC), and other relevant details. Here’s an explanation of
the columns in the dataset:
-
X: Row identifier.
-
site_row_id: Identifier for the site.
-
STATE: State where the gas station is located.
-
county: County where the gas station is located.
-
ADDRESS: Street address of the gas station.
-
CITY: City where the gas station is located.
-
ycoord: Latitude coordinate of the gas station.
-
xcoord: Longitude coordinate of the gas station.
-
SITE_DESCRIPTION: Description of the gas station site.
-
service_or_fuel: Indicates whether the station provides service, fuel,
or both.
-
diesel: Indicates if diesel fuel is available at the station.
-
twentyfour_hour_flag: Indicates if the station operates 24 hours.
-
car_wash: Indicates if the station has a car wash service.
-
truckstop_flag: Indicates if the station is a truck stop.
-
description: Additional description of the gas station.
-
PUMP_TECH: Pump technology used at the gas station.
-
POC: Population of compromised individuals.
-
HIFCA: High Intensity Financial Crime Area.
-
ZIPnew: ZIP code of the gas station.
-
POCAGE: Age distribution of the population of compromised individuals.
-
POCGAP: Age gap distribution of the population of compromised
individuals.
-
ZIPPOC: ZIP code of the population of compromised individuals.
-
HFG: Human Factors Geometry.
-
MSA: Metropolitan Statistical Area.
-
dist.to.poc: Distance to the population of compromised individuals.
-
cate.poc.density: Categorized population of compromised individuals
density.
-
cate.poc.age: Categorized population of compromised individuals age.
-
cate.poc.age.20: Categorized population of compromised individuals age
group 20.
-
cate.poc.intensity: Categorized population of compromised individuals
intensity.
-
cate.poc.intensity.tot: Total categorized population of compromised
individuals intensity.
-
MSA_POC: Metropolitan Statistical Area population of compromised
individuals.
-
MSA_POC.1: Another column indicating Metropolitan Statistical Area
population of compromised individuals.
This dataset contains detailed information about gas stations and the
population they serve, including geographical coordinates, services
offered, and demographic characteristics of the surrounding
population.
gas <- read.csv("https://ecoleman451.github.io/website/Data%20Visualization/Datasets/POC.csv")
Simple Leaflet Map
In the map below, each point represents the precise location of a gas
station, with latitude and longitude coordinates derived from the
“xcoord” and “ycoord” columns in the gas dataset, respectively. Hovering
over each point reveals essential details such as the state, county,
address, and ZIP code associated with that particular gas station.
Explore the interactive map to visualize the distribution of gas
stations across different regions:
gas_samp <- gas %>% sample_n(500)
# Create a leaflet map
gas_map <- leaflet(data = gas_samp) %>%
addTiles() %>%
addMarkers(
lng = ~xcoord,
lat = ~ycoord,
popup = ~paste("State: ", STATE, "<br>",
"County: ", county, "<br>",
"Address: ", ADDRESS, "<br>",
"Zip Code: ", ZIPnew)
)
# Display the map
gas_map
Leaflet Map
Below, we enhance the leaflet map by specifying the radius and color
of the markers. Each marker now appears as a circle with a fixed radius
of 5 and a color set to blue. Similar to the previous map, each circle
represents a gas station, and hovering over a point reveals essential
information such as the state, county, address, and ZIP code associated
with that specific gas station. Explore the interactive map to visualize
the distribution of gas stations with this enhanced visual
representation.
# Create a leaflet map
gas_map2 <- leaflet(data = gas_samp) %>%
addTiles() %>%
setView(lng = mean(gas_samp$xcoord),
lat = mean(gas_samp$ycoord),
zoom = 13) %>%
addProviderTiles("Esri.WorldGrayCanvas") %>%
addCircleMarkers(
~xcoord,
~ycoord,
color = "blue", # Adjust color as needed
radius = 5, # Adjust radius as needed
stroke = FALSE,
fillOpacity = 0.4,
label = ~paste("State: ", STATE,
"County: ", county,
"Address: ", ADDRESS,
"Zip Code: ", ZIPnew)
) %>%
addLegend(position = "bottomright",
colors = "blue", # Adjust color as needed
labels = "Gas Station",
title = "Gas Stations",
opacity = 0.4)
# Display the map
gas_map2
Best Map
In this iteration, we introduce a more sophisticated leaflet map. The
radius of each point on the map is determined by the number of Points of
Compromise (POCs) in the gas station’s ZIP code. Therefore, larger
circles represent ZIP codes with more POCs, providing a visual indicator
of potential risk areas.
Additionally, the color of each point corresponds to the type of
services offered by the gas station: “Fuel”, “Service Only”, or “Both”.
However, since the dataset does not include any gas stations that offer
“Service Only”, only the categories “Fuel” and “Both” will be displayed
on the map.
As with the previous maps, hovering over a point reveals detailed
information such as the state, county, address, and ZIP code associated
with the respective gas station. Explore the map to gain insights into
the distribution of gas stations and their associated services.
# Create a color palette based on service_or_fuel values
service_palette <- colorFactor(palette = "Set1", domain = gas_samp$service_or_fuel)
# Create the leaflet map
gas_map3 <- leaflet(data = gas_samp) %>%
addTiles() %>%
addProviderTiles("Esri.WorldGrayCanvas") %>%
addCircleMarkers(
~xcoord,
~ycoord,
color = ~service_palette(service_or_fuel), # Use colorFactor
radius = gas_samp$ZIPPOC * 10, # Adjust radius as needed
stroke = FALSE,
fillOpacity = 0.4,
label = ~paste("State: ", STATE, "<br>",
"County: ", county, "<br>",
"Address: ", ADDRESS, "<br>",
"Zip Code: ", ZIPnew)
) %>%
addLegend(position = "bottomright",
colors = service_palette(unique(gas_samp$service_or_fuel)), # Use unique service_or_fuel values
labels = unique(gas_samp$service_or_fuel),
title = "Gas Stations",
opacity = 0.4)
# Display the map
gas_map3
Philly Crime Data
The Philadelphia crime dataset contains information on various
incidents, including details such as demographic characteristics,
incident severity, location, and other relevant attributes. Here’s an
explanation of the dataset columns:
-
dc_key: A unique identifier for each incident.
-
race: Specifies the racial background of the individuals involved,
categorized as Black (Non-Hispanic), Hispanic (Black or White), and so
on.
-
sex: Indicates the gender of the individuals involved, classified as
Male or Female.
-
fatal: Indicates whether the incident resulted in a fatality (Fatal) or
not (Nonfatal).
-
date: Records the date and time when the incident occurred.
-
has_court_case: Specifies whether the incident is associated with a
court case (Yes/No).
-
age: Represents the age of the individuals involved in the incident.
-
street_name: Denotes the name of the street where the incident took
place.
-
block_number: Indicates the block number related to the incident’s
location.
-
zip_code: Provides the ZIP code of the incident location.
-
council_district: Identifies the council district corresponding to the
incident location.
-
police_district: Identifies the police district corresponding to the
incident location.
-
neighborhood: Specifies the neighborhood where the incident occurred.
-
house_district: Identifies the house district associated with the
incident location.
-
senate_district: Identifies the senate district associated with the
incident location.
-
school_catchment: Specifies the school catchment area associated with
the incident location.
-
lng: Represents the longitude coordinate of the incident location.
-
lat: Represents the latitude coordinate of the incident location.
This dataset provides valuable insights into the demographics of
individuals involved in various incidents, the nature and severity of
the incidents, and their spatial distribution across different
neighborhoods and districts within Philadelphia. Analyzing this data can
help identify patterns, trends, and areas of concern related to crime
and public safety in the city. We’re narrowing down our dataset to focus
solely on the data from 2023. Since there’s no specific variable
denoting the year, we’ll derive it from the existing ‘date’ variable.
After creating the ‘Year’ variable, we can then filter the data to
include only observations from 2023. Consequently, our updated dataset
now comprises 1666 observations and 19 variables, including the newly
added ‘Year’.
philly <- read.csv("https://ecoleman451.github.io/website/Data%20Visualization/Datasets/PhillyCrimeSince2015.csv")
# Convert date variable to date format
philly$date <- as.Date(philly$date, format = "%m/%d/%Y %H:%M")
# Extract year from date variable
philly$year <- format(philly$date, "%Y")
philly <- subset(philly, year=="2023")
Leaflet Map
Now, let’s visualize fatal versus non-fatal crimes that occurred in
Philadelphia in the year 2023 on a leaflet map. We’ll once again utilize
the “color” function to differentiate between the two types of crimes.
Each category, “Fatal” or “Nonfatal,” will be assigned a distinct color,
providing a visual representation of the crime type. The map follows a
similar format to the ones above, with each circle point denoting a
specific crime incident. Hovering over a point will reveal details such
as the “Neighborhood,” “Date,” “Race,” “Sex,” “Age,” and “Street”
associated with that particular crime. Upon visual inspection of the
map, it appears that there is a notable disparity between the number of
non-fatal crimes and fatal crimes. However, to confirm this observation,
further analysis would be necessary.
library(leaflet)
library(dplyr)
# Create color palette for fatal and non-fatal crimes
fatal <- "red"
non_fatal <- "blue"
# Create leaflet map
map <- leaflet(philly) %>%
addTiles() %>%
addCircleMarkers(
~lng, ~lat,
color = ifelse(philly$fatal == "Fatal", fatal, non_fatal),
radius = 5,
label = ~paste("Neighborhood: ", neighborhood,
"Date: ", date,
"Race: ", race,
"Sex: ", sex,
"Age: ", age,
"Street: ", street_name),
labelOptions = labelOptions(
direction = "auto"
)
) %>%
addLegend(
position = "bottomright",
colors = c(fatal, non_fatal),
labels = c("Fatal", "Non-Fatal"),
title = "Crime Type"
) %>%
addScaleBar() %>%
addControl(
html = "<h4>Philadelphia Crime Locations (2015-2024)</h4>",
position = "topright"
)
# Display the map
map
Better Leaflet Map
Now, let’s create an enhanced leaflet map to visualize fatal versus
non-fatal crimes that occurred in Philadelphia. We’ll utilize the
“color” function once again, with colors representing whether a crime
was labeled as “Fatal” or “Nonfatal”. Each category will be uniquely
colored, offering clear visual identification of the crime type. We’ll
represent each crime location with a circle marker on the map. Hovering
over a point will display detailed information including “Object ID”,
“Year”, “Race”, “Sex”, “Age”, “Wound”, and “Location” for each crime
incident.
# Load required libraries
library(leaflet)
library(sf)
# Suppress messages while reading GeoJSON files
options(warn=-1)
# Read the data without printing messages
philly <- st_read("https://pengdsci.github.io/STA553VIZ/w08/PhillyShootings.geojson", quiet = TRUE)
phillyNeighbor <- st_read("https://pengdsci.github.io/STA553VIZ/w08/Neighborhoods_Philadelphia.geojson", quiet = TRUE)
# Reset warning settings
options(warn=0)
# Convert 'philly' data to sf object
philly_sf <- st_as_sf(philly, coords = c("point_x", "point_y"), crs = 4326)
# Define color palette for fatal and non-fatal crimes
fatal_color <- "red"
non_fatal_color <- "gold"
# Create leaflet map
map <- leaflet() %>%
addProviderTiles(providers$Esri.WorldGrayCanvas) %>%
addPolygons(data = phillyNeighbor,
color = 'skyblue',
weight = 1) %>%
addCircleMarkers(data = philly_sf,
~point_x, ~point_y,
color = ifelse(philly$fatal == 1, fatal_color, non_fatal_color),
radius = 5,
popup = ~paste("Object ID: ", objectid,
"<br>Year: ", year,
"<br>Race: ", race,
"<br>Sex: ", sex,
"<br>Age: ", age,
"<br>Wound: ", wound,
"<br>Location: ", location),
labelOptions = labelOptions(
direction = "auto"
)
) %>%
addLegend(
position = "bottomright",
colors = c("red", "gold"),
labels = c("Fatal", "Non-Fatal"),
title = "Crime Type"
) %>%
addScaleBar() %>%
addControl(
html = "<h4>Philadelphia Crime Locations (2015-2024)</h4>",
position = "topright"
) %>%
addProviderTiles(providers$Esri.WorldGrayCanvas) %>%
setView(lng = -75.1527, lat = 39.9707, zoom = 11)
# Display the map
map
U.S. Presidential Election Data (2000-2024)
Our initial dataset, named “election”, encompasses Presidential
election outcomes spanning the years 2000, 2004, 2008, 2012, 2016, and
2020. With 72,617 observations and 12 variables, it provides
comprehensive insights into each state’s and county’s election results,
detailing the winning candidate in each county, along with the total
votes received by each candidate.
Prior to analysis, some data cleaning was imperative, particularly
concerning the county FIPS codes—a unique 5-digit identifier assigned to
every county in the United States. Initially, certain codes erroneously
contained only 4 digits, notably when a “0” preceded the first digit.
For instance, Autauga County, Alabama’s FIPS code “01001” was recorded
as “1001” in the dataset. This discrepancy was rectified using the
“TEXT” function in Excel, applied before importing the data into the
“election” set.
Utilizing the “election” dataset, our objective is to split the data
into county-level and state-level subsets. Both subsets include a new
variable named “party_percentage,” calculated to ascertain the
percentage of voters favoring the winning party within their respective
state or county. The “county_data” subset provides election results
categorized by county, while the “state_data” subset presents election
outcomes aggregated by state. Furthermore, both subsets retain solely
the winning party’s information for analysis.
# Load the required library
library(dplyr)
# Read the data
election <- read.csv("https://ecoleman451.github.io/website/Data%20Visualization/Datasets/PresidentialElection2000To2020.csv")
# County-level Data
county_data <- election %>%
group_by(year, state, county_name) %>%
mutate(party_percentage = candidatevotes / sum(candidatevotes) * 100) %>%
filter(party_percentage == max(party_percentage)) %>%
select(year, state, county_fips, party, candidate, candidatevotes, party_percentage)
# State-level Data
state_data <- election %>%
group_by(year, state) %>%
mutate(party_percentage = candidatevotes / sum(candidatevotes) * 100) %>%
filter(party_percentage == max(party_percentage)) %>%
select(year, state, party, candidate, candidatevotes, party_percentage)
# Save county-level data to a new CSV file
write.csv(county_data, file = "county_level_data.csv", row.names = FALSE)
# Save state-level data to a new CSV file
write.csv(state_data, file = "state_level_data.csv", row.names = FALSE)
Choropleth Map
Now that we’ve split the dataset into “county_data,” focusing solely on
election results (specifically the winning party) at the county level,
we can leverage Tableau, an interactive data visualization tool, to
craft a Choropleth Map. This map will display presidential election
outcomes at the county level. Different colors are assigned to represent
the major political parties (Democrat & Republican), and each
county’s shading reflects the winning political party in a specific
election year. The interactive map includes a filter to alter the
displayed year(s). Additionally, hover text appears when hovering over a
specific county on the map, providing information such as “year,”
“state,” “party,” “candidatevotes,” and “party_percentage” for the
respective county.
LS0tDQp0aXRsZTogIk1hcHBpbmciDQphdXRob3I6ICJFZHdhcmQgQ29sZW1hbiINCmRhdGU6ICJXZXN0IENoZXN0ZXIgVW5pdmVyc2l0eSINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHNtb290aF9zY3JvbGw6IHllcw0KICAgIHRoZW1lOiByZWFkYWJsZQ0KICAgIGVkaXRvcl9vcHRpb25zOg0KICAgICAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQovKiBDb21tb24gc3R5bGVzICovDQpkaXYjVE9DIGxpIHsNCiAgICBsaXN0LXN0eWxlOm5vbmU7DQogICAgYmFja2dyb3VuZC1jb2xvcjpsaWdodGdyYXk7DQogICAgYmFja2dyb3VuZC1pbWFnZTpub25lOw0KICAgIGJhY2tncm91bmQtcmVwZWF0Om5vbmU7DQogICAgYmFja2dyb3VuZC1wb3NpdGlvbjowOw0KICAgIGZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOw0KICAgIGNvbG9yOiAjNzgwYzBjOw0KfQ0KDQpoMS50aXRsZSB7DQogICAgZm9udC1zaXplOiAyNHB4Ow0KICAgIGNvbG9yOiBEYXJrUmVkOw0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgICBmb250LWZhbWlseTogQXJpYWwsIEhlbHZldGljYSwgc2Fucy1zZXJpZjsNCiAgICBmb250LXZhcmlhbnQtY2Fwczogbm9ybWFsOw0KfQ0KaDQuYXV0aG9yIHsgDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBEYXJrUmVkOw0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmg0LmRhdGUgeyANCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IERhcmtCbHVlOw0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmgxIHsgDQogICAgZm9udC1zaXplOiAyMnB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmgyIHsgDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQpoMyB7IA0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KaDQgeyANCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KLyogVGFiIGZlYXR1cmVzICovDQoubmF2PmxpPmEgew0KICAgIHBvc2l0aW9uOiByZWxhdGl2ZTsNCiAgICBkaXNwbGF5OiBibG9jazsNCiAgICBwYWRkaW5nOiAycHggMTVweDsNCiAgICBjb2xvcjogIzk5MDAwMDsNCn0NCi5uYXYtcGlsbHM+bGkuYWN0aXZlPmEsIC5uYXYtcGlsbHM+bGkuYWN0aXZlPmE6aG92ZXIsIC5uYXYtcGlsbHM+bGkuYWN0aXZlPmE6Zm9jdXMgew0KICAgIGNvbG9yOiAjZmZmZmZmOw0KICAgIGJhY2tncm91bmQtY29sb3I6ICM5OTAwMDA7DQp9DQovKg0KbmF2LXBpbGxzPmxpOm50aC1jaGlsZCgyKSB7DQogICAgYmFja2dyb3VuZDogZ3JlZW47DQogfQ0KICovDQppbWcgew0KICAgIGJvcmRlcjogMXB4IHNvbGlkICM1NTU7DQp9DQoNCi8qIFJlbW92ZSBib3JkZXIgZnJvbSBsZWFmbGV0IG1hcmtlciBpbWFnZXMgKi8NCi5sZWFmbGV0LXBhbmUgaW1nLmxlYWZsZXQtbWFya2VyLWljb24gew0KICAgIGJvcmRlcjogbm9uZSAhaW1wb3J0YW50Ow0KfQ0KPC9zdHlsZT4NCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRSwgY29tbWVudD1OQX0NCm9wdGlvbnMocmVwb3MgPSBsaXN0KENSQU49Imh0dHA6Ly9jcmFuLnJzdHVkaW8uY29tLyIpKQ0KaWYgKCFyZXF1aXJlKCJ0aWR5dmVyc2UiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCiAgIGxpYnJhcnkodGlkeXZlcnNlKQ0KfQ0KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQogICBsaWJyYXJ5KGtuaXRyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJjb3dwbG90IikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImNvd3Bsb3QiKQ0KICAgbGlicmFyeShjb3dwbG90KQ0KfQ0KaWYgKCFyZXF1aXJlKCJsYXRleDJleHAiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygibGF0ZXgyZXhwIikNCiAgIGxpYnJhcnkobGF0ZXgyZXhwKQ0KfQ0KaWYgKCFyZXF1aXJlKCJwbG90bHkiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikNCiAgIGxpYnJhcnkocGxvdGx5KQ0KfQ0KaWYgKCFyZXF1aXJlKCJnYXBtaW5kZXIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiZ2FwbWluZGVyIikNCiAgIGxpYnJhcnkoZ2FwbWluZGVyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJwbmciKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoInBuZyIpICAgIA0KICAgIGxpYnJhcnkoInBuZyIpDQp9DQppZiAoIXJlcXVpcmUoIlJDdXJsIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJSQ3VybCIpICAgIA0KICAgIGxpYnJhcnkoIlJDdXJsIikNCn0NCmlmICghcmVxdWlyZSgiY29sb3VycGlja2VyIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJjb2xvdXJwaWNrZXIiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiY29sb3VycGlja2VyIikNCn0NCmlmICghcmVxdWlyZSgiZ2dhbmltYXRlIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJnZ2FuaW1hdGUiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZ2dhbmltYXRlIikNCn0NCmlmICghcmVxdWlyZSgiZ2lmc2tpIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJnaWZza2kiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZ2lmc2tpIikNCn0NCmlmICghcmVxdWlyZSgibWFnaWNrIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJtYWdpY2siKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgibWFnaWNrIikNCn0NCmlmICghcmVxdWlyZSgiZ3JEZXZpY2VzIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJnckRldmljZXMiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZ3JEZXZpY2VzIikNCn0NCmlmICghcmVxdWlyZSgianBlZyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygianBlZyIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJqcGVnIikNCn0NCmlmICghcmVxdWlyZSgiZ2dyaWRnZXMiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdncmlkZ2VzIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImdncmlkZ2VzIikNCn0NCmlmICghcmVxdWlyZSgicGx5ciIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygicGx5ciIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJwbHlyIikNCn0NCmlmICghcmVxdWlyZSgiZ2dpcmFwaCIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiZ2dpcmFwaCIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJnZ2lyYXBoIikNCn0NCmlmICghcmVxdWlyZSgiaGlnaGNoYXJ0ZXIiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImhpZ2hjaGFydGVyIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImhpZ2hjaGFydGVyIikNCn0NCmlmICghcmVxdWlyZSgiZm9yZWNhc3QiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImZvcmVjYXN0IikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImZvcmVjYXN0IikNCn0NCmlmICghcmVxdWlyZSgibGVhZmxldCIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygibGVhZmxldCIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJsZWFmbGV0IikNCn0NCmlmICghcmVxdWlyZSgic2YiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoInNmIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoInNmIikNCn0NCiMjIA0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsICAgDQogICAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0gVFJVRSwgICANCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgY29tbWVudCA9IE5BKQ0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IA0KIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuDQppZiAoIXJlcXVpcmUoIlN0YXQyRGF0YSIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJTdGF0MkRhdGEiKQ0KICAgbGlicmFyeShTdGF0MkRhdGEpDQp9DQppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCiAgIGxpYnJhcnkoa25pdHIpDQp9DQoNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IFRSVUUsICAgDQogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIGNvbW1lbnQgPSBOQSkNCmBgYA0KDQojIEdhcyBEYXRhDQogIFRoZSBnYXMgZGF0YSByZXByZXNlbnRzIGluZm9ybWF0aW9uIGFib3V0IHZhcmlvdXMgZ2FzIHN0YXRpb25zLCBpbmNsdWRpbmcgdGhlaXIgbG9jYXRpb24sIHNlcnZpY2VzIG9mZmVyZWQsIHBvcHVsYXRpb24gb2YgY29tcHJvbWlzZWQgaW5kaXZpZHVhbHMgKFBPQyksIGFuZCBvdGhlciByZWxldmFudCBkZXRhaWxzLiBIZXJlJ3MgYW4gZXhwbGFuYXRpb24gb2YgdGhlIGNvbHVtbnMgaW4gdGhlIGRhdGFzZXQ6DQoNCjx1bD4NCiAgPGxpPlg6IFJvdyBpZGVudGlmaWVyLjwvbGk+DQogIDxsaT5zaXRlX3Jvd19pZDogSWRlbnRpZmllciBmb3IgdGhlIHNpdGUuPC9saT4NCiAgPGxpPlNUQVRFOiBTdGF0ZSB3aGVyZSB0aGUgZ2FzIHN0YXRpb24gaXMgbG9jYXRlZC48L2xpPg0KICA8bGk+Y291bnR5OiBDb3VudHkgd2hlcmUgdGhlIGdhcyBzdGF0aW9uIGlzIGxvY2F0ZWQuPC9saT4NCiAgPGxpPkFERFJFU1M6IFN0cmVldCBhZGRyZXNzIG9mIHRoZSBnYXMgc3RhdGlvbi48L2xpPg0KICA8bGk+Q0lUWTogQ2l0eSB3aGVyZSB0aGUgZ2FzIHN0YXRpb24gaXMgbG9jYXRlZC48L2xpPg0KICA8bGk+eWNvb3JkOiBMYXRpdHVkZSBjb29yZGluYXRlIG9mIHRoZSBnYXMgc3RhdGlvbi48L2xpPg0KICA8bGk+eGNvb3JkOiBMb25naXR1ZGUgY29vcmRpbmF0ZSBvZiB0aGUgZ2FzIHN0YXRpb24uPC9saT4NCiAgPGxpPlNJVEVfREVTQ1JJUFRJT046IERlc2NyaXB0aW9uIG9mIHRoZSBnYXMgc3RhdGlvbiBzaXRlLjwvbGk+DQogIDxsaT5zZXJ2aWNlX29yX2Z1ZWw6IEluZGljYXRlcyB3aGV0aGVyIHRoZSBzdGF0aW9uIHByb3ZpZGVzIHNlcnZpY2UsIGZ1ZWwsIG9yIGJvdGguPC9saT4NCiAgPGxpPmRpZXNlbDogSW5kaWNhdGVzIGlmIGRpZXNlbCBmdWVsIGlzIGF2YWlsYWJsZSBhdCB0aGUgc3RhdGlvbi48L2xpPg0KICA8bGk+dHdlbnR5Zm91cl9ob3VyX2ZsYWc6IEluZGljYXRlcyBpZiB0aGUgc3RhdGlvbiBvcGVyYXRlcyAyNCBob3Vycy48L2xpPg0KICA8bGk+Y2FyX3dhc2g6IEluZGljYXRlcyBpZiB0aGUgc3RhdGlvbiBoYXMgYSBjYXIgd2FzaCBzZXJ2aWNlLjwvbGk+DQogIDxsaT50cnVja3N0b3BfZmxhZzogSW5kaWNhdGVzIGlmIHRoZSBzdGF0aW9uIGlzIGEgdHJ1Y2sgc3RvcC48L2xpPg0KICA8bGk+ZGVzY3JpcHRpb246IEFkZGl0aW9uYWwgZGVzY3JpcHRpb24gb2YgdGhlIGdhcyBzdGF0aW9uLjwvbGk+DQogIDxsaT5QVU1QX1RFQ0g6IFB1bXAgdGVjaG5vbG9neSB1c2VkIGF0IHRoZSBnYXMgc3RhdGlvbi48L2xpPg0KICA8bGk+UE9DOiBQb3B1bGF0aW9uIG9mIGNvbXByb21pc2VkIGluZGl2aWR1YWxzLjwvbGk+DQogIDxsaT5ISUZDQTogSGlnaCBJbnRlbnNpdHkgRmluYW5jaWFsIENyaW1lIEFyZWEuPC9saT4NCiAgPGxpPlpJUG5ldzogWklQIGNvZGUgb2YgdGhlIGdhcyBzdGF0aW9uLjwvbGk+DQogIDxsaT5QT0NBR0U6IEFnZSBkaXN0cmlidXRpb24gb2YgdGhlIHBvcHVsYXRpb24gb2YgY29tcHJvbWlzZWQgaW5kaXZpZHVhbHMuPC9saT4NCiAgPGxpPlBPQ0dBUDogQWdlIGdhcCBkaXN0cmlidXRpb24gb2YgdGhlIHBvcHVsYXRpb24gb2YgY29tcHJvbWlzZWQgaW5kaXZpZHVhbHMuPC9saT4NCiAgPGxpPlpJUFBPQzogWklQIGNvZGUgb2YgdGhlIHBvcHVsYXRpb24gb2YgY29tcHJvbWlzZWQgaW5kaXZpZHVhbHMuPC9saT4NCiAgPGxpPkhGRzogSHVtYW4gRmFjdG9ycyBHZW9tZXRyeS48L2xpPg0KICA8bGk+TVNBOiBNZXRyb3BvbGl0YW4gU3RhdGlzdGljYWwgQXJlYS48L2xpPg0KICA8bGk+ZGlzdC50by5wb2M6IERpc3RhbmNlIHRvIHRoZSBwb3B1bGF0aW9uIG9mIGNvbXByb21pc2VkIGluZGl2aWR1YWxzLjwvbGk+DQogIDxsaT5jYXRlLnBvYy5kZW5zaXR5OiBDYXRlZ29yaXplZCBwb3B1bGF0aW9uIG9mIGNvbXByb21pc2VkIGluZGl2aWR1YWxzIGRlbnNpdHkuPC9saT4NCiAgPGxpPmNhdGUucG9jLmFnZTogQ2F0ZWdvcml6ZWQgcG9wdWxhdGlvbiBvZiBjb21wcm9taXNlZCBpbmRpdmlkdWFscyBhZ2UuPC9saT4NCiAgPGxpPmNhdGUucG9jLmFnZS4yMDogQ2F0ZWdvcml6ZWQgcG9wdWxhdGlvbiBvZiBjb21wcm9taXNlZCBpbmRpdmlkdWFscyBhZ2UgZ3JvdXAgMjAuPC9saT4NCiAgPGxpPmNhdGUucG9jLmludGVuc2l0eTogQ2F0ZWdvcml6ZWQgcG9wdWxhdGlvbiBvZiBjb21wcm9taXNlZCBpbmRpdmlkdWFscyBpbnRlbnNpdHkuPC9saT4NCiAgPGxpPmNhdGUucG9jLmludGVuc2l0eS50b3Q6IFRvdGFsIGNhdGVnb3JpemVkIHBvcHVsYXRpb24gb2YgY29tcHJvbWlzZWQgaW5kaXZpZHVhbHMgaW50ZW5zaXR5LjwvbGk+DQogIDxsaT5NU0FfUE9DOiBNZXRyb3BvbGl0YW4gU3RhdGlzdGljYWwgQXJlYSBwb3B1bGF0aW9uIG9mIGNvbXByb21pc2VkIGluZGl2aWR1YWxzLjwvbGk+DQogIDxsaT5NU0FfUE9DLjE6IEFub3RoZXIgY29sdW1uIGluZGljYXRpbmcgTWV0cm9wb2xpdGFuIFN0YXRpc3RpY2FsIEFyZWEgcG9wdWxhdGlvbiBvZiBjb21wcm9taXNlZCBpbmRpdmlkdWFscy48L2xpPg0KPC91bD4NCg0KVGhpcyBkYXRhc2V0IGNvbnRhaW5zIGRldGFpbGVkIGluZm9ybWF0aW9uIGFib3V0IGdhcyBzdGF0aW9ucyBhbmQgdGhlIHBvcHVsYXRpb24gdGhleSBzZXJ2ZSwgaW5jbHVkaW5nIGdlb2dyYXBoaWNhbCBjb29yZGluYXRlcywgc2VydmljZXMgb2ZmZXJlZCwgYW5kIGRlbW9ncmFwaGljIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgc3Vycm91bmRpbmcgcG9wdWxhdGlvbi4NCmBgYHtyLCBjb21tZW50PU5BfQ0KZ2FzIDwtIHJlYWQuY3N2KCJodHRwczovL2Vjb2xlbWFuNDUxLmdpdGh1Yi5pby93ZWJzaXRlL0RhdGElMjBWaXN1YWxpemF0aW9uL0RhdGFzZXRzL1BPQy5jc3YiKQ0KYGBgDQoNCiMjIFNpbXBsZSBMZWFmbGV0IE1hcA0KICBJbiB0aGUgbWFwIGJlbG93LCBlYWNoIHBvaW50IHJlcHJlc2VudHMgdGhlIHByZWNpc2UgbG9jYXRpb24gb2YgYSBnYXMgc3RhdGlvbiwgd2l0aCBsYXRpdHVkZSBhbmQgbG9uZ2l0dWRlIGNvb3JkaW5hdGVzIGRlcml2ZWQgZnJvbSB0aGUgInhjb29yZCIgYW5kICJ5Y29vcmQiIGNvbHVtbnMgaW4gdGhlIGdhcyBkYXRhc2V0LCByZXNwZWN0aXZlbHkuIEhvdmVyaW5nIG92ZXIgZWFjaCBwb2ludCByZXZlYWxzIGVzc2VudGlhbCBkZXRhaWxzIHN1Y2ggYXMgdGhlIHN0YXRlLCBjb3VudHksIGFkZHJlc3MsIGFuZCBaSVAgY29kZSBhc3NvY2lhdGVkIHdpdGggdGhhdCBwYXJ0aWN1bGFyIGdhcyBzdGF0aW9uLiBFeHBsb3JlIHRoZSBpbnRlcmFjdGl2ZSBtYXAgdG8gdmlzdWFsaXplIHRoZSBkaXN0cmlidXRpb24gb2YgZ2FzIHN0YXRpb25zIGFjcm9zcyBkaWZmZXJlbnQgcmVnaW9uczoNCmBgYHtyLCBjb21tZW50PU5BfQ0KIGdhc19zYW1wIDwtIGdhcyAlPiUgc2FtcGxlX24oNTAwKQ0KDQojIENyZWF0ZSBhIGxlYWZsZXQgbWFwDQpnYXNfbWFwIDwtIGxlYWZsZXQoZGF0YSA9IGdhc19zYW1wKSAlPiUNCiAgYWRkVGlsZXMoKSAlPiUNCiAgYWRkTWFya2VycygNCiAgICBsbmcgPSB+eGNvb3JkLA0KICAgIGxhdCA9IH55Y29vcmQsDQogICAgcG9wdXAgPSB+cGFzdGUoIlN0YXRlOiAiLCBTVEFURSwgIjxicj4iLA0KICAgICAgICAgICAgICAgICAgICJDb3VudHk6ICIsIGNvdW50eSwgIjxicj4iLA0KICAgICAgICAgICAgICAgICAgICJBZGRyZXNzOiAiLCBBRERSRVNTLCAiPGJyPiIsDQogICAgICAgICAgICAgICAgICAgIlppcCBDb2RlOiAiLCBaSVBuZXcpDQogICkNCiMgRGlzcGxheSB0aGUgbWFwDQpnYXNfbWFwDQpgYGANCg0KIyMgTGVhZmxldCBNYXANCiAgQmVsb3csIHdlIGVuaGFuY2UgdGhlIGxlYWZsZXQgbWFwIGJ5IHNwZWNpZnlpbmcgdGhlIHJhZGl1cyBhbmQgY29sb3Igb2YgdGhlIG1hcmtlcnMuIEVhY2ggbWFya2VyIG5vdyBhcHBlYXJzIGFzIGEgY2lyY2xlIHdpdGggYSBmaXhlZCByYWRpdXMgb2YgNSBhbmQgYSBjb2xvciBzZXQgdG8gYmx1ZS4gU2ltaWxhciB0byB0aGUgcHJldmlvdXMgbWFwLCBlYWNoIGNpcmNsZSByZXByZXNlbnRzIGEgZ2FzIHN0YXRpb24sIGFuZCBob3ZlcmluZyBvdmVyIGEgcG9pbnQgcmV2ZWFscyBlc3NlbnRpYWwgaW5mb3JtYXRpb24gc3VjaCBhcyB0aGUgc3RhdGUsIGNvdW50eSwgYWRkcmVzcywgYW5kIFpJUCBjb2RlIGFzc29jaWF0ZWQgd2l0aCB0aGF0IHNwZWNpZmljIGdhcyBzdGF0aW9uLiBFeHBsb3JlIHRoZSBpbnRlcmFjdGl2ZSBtYXAgdG8gdmlzdWFsaXplIHRoZSBkaXN0cmlidXRpb24gb2YgZ2FzIHN0YXRpb25zIHdpdGggdGhpcyBlbmhhbmNlZCB2aXN1YWwgcmVwcmVzZW50YXRpb24uDQpgYGB7ciwgY29tbWVudD1OQX0NCiMgQ3JlYXRlIGEgbGVhZmxldCBtYXANCmdhc19tYXAyIDwtIGxlYWZsZXQoZGF0YSA9IGdhc19zYW1wKSAlPiUNCiAgYWRkVGlsZXMoKSAlPiUNCiAgc2V0VmlldyhsbmcgPSBtZWFuKGdhc19zYW1wJHhjb29yZCksIA0KICAgICAgICAgIGxhdCA9IG1lYW4oZ2FzX3NhbXAkeWNvb3JkKSwgDQogICAgICAgICAgem9vbSA9IDEzKSAlPiUNCiAgYWRkUHJvdmlkZXJUaWxlcygiRXNyaS5Xb3JsZEdyYXlDYW52YXMiKSAlPiUNCiAgYWRkQ2lyY2xlTWFya2VycygNCiAgICB+eGNvb3JkLCANCiAgICB+eWNvb3JkLA0KICAgIGNvbG9yID0gImJsdWUiLCAgIyBBZGp1c3QgY29sb3IgYXMgbmVlZGVkDQogICAgcmFkaXVzID0gNSwgICMgQWRqdXN0IHJhZGl1cyBhcyBuZWVkZWQNCiAgICBzdHJva2UgPSBGQUxTRSwgDQogICAgZmlsbE9wYWNpdHkgPSAwLjQsDQogICAgbGFiZWwgPSB+cGFzdGUoIlN0YXRlOiAiLCBTVEFURSwNCiAgICAgICAgICAgICAgICAgICAiQ291bnR5OiAiLCBjb3VudHksDQogICAgICAgICAgICAgICAgICAgIkFkZHJlc3M6ICIsIEFERFJFU1MsDQogICAgICAgICAgICAgICAgICAgIlppcCBDb2RlOiAiLCBaSVBuZXcpDQogICkgJT4lDQogIGFkZExlZ2VuZChwb3NpdGlvbiA9ICJib3R0b21yaWdodCIsIA0KICAgICAgICAgICAgY29sb3JzID0gImJsdWUiLCAgIyBBZGp1c3QgY29sb3IgYXMgbmVlZGVkDQogICAgICAgICAgICBsYWJlbHMgPSAiR2FzIFN0YXRpb24iLA0KICAgICAgICAgICAgdGl0bGUgPSAiR2FzIFN0YXRpb25zIiwNCiAgICAgICAgICAgIG9wYWNpdHkgPSAwLjQpDQoNCiMgRGlzcGxheSB0aGUgbWFwDQpnYXNfbWFwMg0KYGBgDQoNCiMjIEJlc3QgTWFwDQpJbiB0aGlzIGl0ZXJhdGlvbiwgd2UgaW50cm9kdWNlIGEgbW9yZSBzb3BoaXN0aWNhdGVkIGxlYWZsZXQgbWFwLiBUaGUgcmFkaXVzIG9mIGVhY2ggcG9pbnQgb24gdGhlIG1hcCBpcyBkZXRlcm1pbmVkIGJ5IHRoZSBudW1iZXIgb2YgUG9pbnRzIG9mIENvbXByb21pc2UgKFBPQ3MpIGluIHRoZSBnYXMgc3RhdGlvbidzIFpJUCBjb2RlLiBUaGVyZWZvcmUsIGxhcmdlciBjaXJjbGVzIHJlcHJlc2VudCBaSVAgY29kZXMgd2l0aCBtb3JlIFBPQ3MsIHByb3ZpZGluZyBhIHZpc3VhbCBpbmRpY2F0b3Igb2YgcG90ZW50aWFsIHJpc2sgYXJlYXMuDQoNCkFkZGl0aW9uYWxseSwgdGhlIGNvbG9yIG9mIGVhY2ggcG9pbnQgY29ycmVzcG9uZHMgdG8gdGhlIHR5cGUgb2Ygc2VydmljZXMgb2ZmZXJlZCBieSB0aGUgZ2FzIHN0YXRpb246ICJGdWVsIiwgIlNlcnZpY2UgT25seSIsIG9yICJCb3RoIi4gSG93ZXZlciwgc2luY2UgdGhlIGRhdGFzZXQgZG9lcyBub3QgaW5jbHVkZSBhbnkgZ2FzIHN0YXRpb25zIHRoYXQgb2ZmZXIgIlNlcnZpY2UgT25seSIsIG9ubHkgdGhlIGNhdGVnb3JpZXMgIkZ1ZWwiIGFuZCAiQm90aCIgd2lsbCBiZSBkaXNwbGF5ZWQgb24gdGhlIG1hcC4NCg0KQXMgd2l0aCB0aGUgcHJldmlvdXMgbWFwcywgaG92ZXJpbmcgb3ZlciBhIHBvaW50IHJldmVhbHMgZGV0YWlsZWQgaW5mb3JtYXRpb24gc3VjaCBhcyB0aGUgc3RhdGUsIGNvdW50eSwgYWRkcmVzcywgYW5kIFpJUCBjb2RlIGFzc29jaWF0ZWQgd2l0aCB0aGUgcmVzcGVjdGl2ZSBnYXMgc3RhdGlvbi4gRXhwbG9yZSB0aGUgbWFwIHRvIGdhaW4gaW5zaWdodHMgaW50byB0aGUgZGlzdHJpYnV0aW9uIG9mIGdhcyBzdGF0aW9ucyBhbmQgdGhlaXIgYXNzb2NpYXRlZCBzZXJ2aWNlcy4NCmBgYHtyLCBjb21tZW50PU5BfQ0KIyBDcmVhdGUgYSBjb2xvciBwYWxldHRlIGJhc2VkIG9uIHNlcnZpY2Vfb3JfZnVlbCB2YWx1ZXMNCnNlcnZpY2VfcGFsZXR0ZSA8LSBjb2xvckZhY3RvcihwYWxldHRlID0gIlNldDEiLCBkb21haW4gPSBnYXNfc2FtcCRzZXJ2aWNlX29yX2Z1ZWwpDQoNCiMgQ3JlYXRlIHRoZSBsZWFmbGV0IG1hcA0KZ2FzX21hcDMgPC0gbGVhZmxldChkYXRhID0gZ2FzX3NhbXApICU+JQ0KICBhZGRUaWxlcygpICU+JQ0KICBhZGRQcm92aWRlclRpbGVzKCJFc3JpLldvcmxkR3JheUNhbnZhcyIpICU+JQ0KICBhZGRDaXJjbGVNYXJrZXJzKA0KICAgIH54Y29vcmQsIA0KICAgIH55Y29vcmQsDQogICAgY29sb3IgPSB+c2VydmljZV9wYWxldHRlKHNlcnZpY2Vfb3JfZnVlbCksICAjIFVzZSBjb2xvckZhY3Rvcg0KICAgIHJhZGl1cyA9IGdhc19zYW1wJFpJUFBPQyAqIDEwLCAgIyBBZGp1c3QgcmFkaXVzIGFzIG5lZWRlZA0KICAgIHN0cm9rZSA9IEZBTFNFLCANCiAgICBmaWxsT3BhY2l0eSA9IDAuNCwNCiAgICBsYWJlbCA9IH5wYXN0ZSgiU3RhdGU6ICIsIFNUQVRFLCAiPGJyPiIsDQogICAgICAgICAgICAgICAgICAgIkNvdW50eTogIiwgY291bnR5LCAiPGJyPiIsDQogICAgICAgICAgICAgICAgICAgIkFkZHJlc3M6ICIsIEFERFJFU1MsICI8YnI+IiwNCiAgICAgICAgICAgICAgICAgICAiWmlwIENvZGU6ICIsIFpJUG5ldykNCiAgKSAlPiUNCiAgYWRkTGVnZW5kKHBvc2l0aW9uID0gImJvdHRvbXJpZ2h0IiwgDQogICAgICAgICAgICBjb2xvcnMgPSBzZXJ2aWNlX3BhbGV0dGUodW5pcXVlKGdhc19zYW1wJHNlcnZpY2Vfb3JfZnVlbCkpLCAgIyBVc2UgdW5pcXVlIHNlcnZpY2Vfb3JfZnVlbCB2YWx1ZXMNCiAgICAgICAgICAgIGxhYmVscyA9IHVuaXF1ZShnYXNfc2FtcCRzZXJ2aWNlX29yX2Z1ZWwpLA0KICAgICAgICAgICAgdGl0bGUgPSAiR2FzIFN0YXRpb25zIiwNCiAgICAgICAgICAgIG9wYWNpdHkgPSAwLjQpDQoNCiMgRGlzcGxheSB0aGUgbWFwDQpnYXNfbWFwMw0KYGBgDQoNCg0KIyBQaGlsbHkgQ3JpbWUgRGF0YQ0KVGhlIFBoaWxhZGVscGhpYSBjcmltZSBkYXRhc2V0IGNvbnRhaW5zIGluZm9ybWF0aW9uIG9uIHZhcmlvdXMgaW5jaWRlbnRzLCBpbmNsdWRpbmcgZGV0YWlscyBzdWNoIGFzIGRlbW9ncmFwaGljIGNoYXJhY3RlcmlzdGljcywgaW5jaWRlbnQgc2V2ZXJpdHksIGxvY2F0aW9uLCBhbmQgb3RoZXIgcmVsZXZhbnQgYXR0cmlidXRlcy4gSGVyZSdzIGFuIGV4cGxhbmF0aW9uIG9mIHRoZSBkYXRhc2V0IGNvbHVtbnM6DQoNCjx1bD4NCiAgPGxpPmRjX2tleTogQSB1bmlxdWUgaWRlbnRpZmllciBmb3IgZWFjaCBpbmNpZGVudC48L2xpPg0KICA8bGk+cmFjZTogU3BlY2lmaWVzIHRoZSByYWNpYWwgYmFja2dyb3VuZCBvZiB0aGUgaW5kaXZpZHVhbHMgaW52b2x2ZWQsIGNhdGVnb3JpemVkIGFzIEJsYWNrIChOb24tSGlzcGFuaWMpLCBIaXNwYW5pYyAoQmxhY2sgb3IgV2hpdGUpLCBhbmQgc28gb24uPC9saT4NCiAgPGxpPnNleDogSW5kaWNhdGVzIHRoZSBnZW5kZXIgb2YgdGhlIGluZGl2aWR1YWxzIGludm9sdmVkLCBjbGFzc2lmaWVkIGFzIE1hbGUgb3IgRmVtYWxlLjwvbGk+DQogIDxsaT5mYXRhbDogSW5kaWNhdGVzIHdoZXRoZXIgdGhlIGluY2lkZW50IHJlc3VsdGVkIGluIGEgZmF0YWxpdHkgKEZhdGFsKSBvciBub3QgKE5vbmZhdGFsKS48L2xpPg0KICA8bGk+ZGF0ZTogUmVjb3JkcyB0aGUgZGF0ZSBhbmQgdGltZSB3aGVuIHRoZSBpbmNpZGVudCBvY2N1cnJlZC48L2xpPg0KICA8bGk+aGFzX2NvdXJ0X2Nhc2U6IFNwZWNpZmllcyB3aGV0aGVyIHRoZSBpbmNpZGVudCBpcyBhc3NvY2lhdGVkIHdpdGggYSBjb3VydCBjYXNlIChZZXMvTm8pLjwvbGk+DQogIDxsaT5hZ2U6IFJlcHJlc2VudHMgdGhlIGFnZSBvZiB0aGUgaW5kaXZpZHVhbHMgaW52b2x2ZWQgaW4gdGhlIGluY2lkZW50LjwvbGk+DQogIDxsaT5zdHJlZXRfbmFtZTogRGVub3RlcyB0aGUgbmFtZSBvZiB0aGUgc3RyZWV0IHdoZXJlIHRoZSBpbmNpZGVudCB0b29rIHBsYWNlLjwvbGk+DQogIDxsaT5ibG9ja19udW1iZXI6IEluZGljYXRlcyB0aGUgYmxvY2sgbnVtYmVyIHJlbGF0ZWQgdG8gdGhlIGluY2lkZW50J3MgbG9jYXRpb24uPC9saT4NCiAgPGxpPnppcF9jb2RlOiBQcm92aWRlcyB0aGUgWklQIGNvZGUgb2YgdGhlIGluY2lkZW50IGxvY2F0aW9uLjwvbGk+DQogIDxsaT5jb3VuY2lsX2Rpc3RyaWN0OiBJZGVudGlmaWVzIHRoZSBjb3VuY2lsIGRpc3RyaWN0IGNvcnJlc3BvbmRpbmcgdG8gdGhlIGluY2lkZW50IGxvY2F0aW9uLjwvbGk+DQogIDxsaT5wb2xpY2VfZGlzdHJpY3Q6IElkZW50aWZpZXMgdGhlIHBvbGljZSBkaXN0cmljdCBjb3JyZXNwb25kaW5nIHRvIHRoZSBpbmNpZGVudCBsb2NhdGlvbi48L2xpPg0KICA8bGk+bmVpZ2hib3Job29kOiBTcGVjaWZpZXMgdGhlIG5laWdoYm9yaG9vZCB3aGVyZSB0aGUgaW5jaWRlbnQgb2NjdXJyZWQuPC9saT4NCiAgPGxpPmhvdXNlX2Rpc3RyaWN0OiBJZGVudGlmaWVzIHRoZSBob3VzZSBkaXN0cmljdCBhc3NvY2lhdGVkIHdpdGggdGhlIGluY2lkZW50IGxvY2F0aW9uLjwvbGk+DQogIDxsaT5zZW5hdGVfZGlzdHJpY3Q6IElkZW50aWZpZXMgdGhlIHNlbmF0ZSBkaXN0cmljdCBhc3NvY2lhdGVkIHdpdGggdGhlIGluY2lkZW50IGxvY2F0aW9uLjwvbGk+DQogIDxsaT5zY2hvb2xfY2F0Y2htZW50OiBTcGVjaWZpZXMgdGhlIHNjaG9vbCBjYXRjaG1lbnQgYXJlYSBhc3NvY2lhdGVkIHdpdGggdGhlIGluY2lkZW50IGxvY2F0aW9uLjwvbGk+DQogIDxsaT5sbmc6IFJlcHJlc2VudHMgdGhlIGxvbmdpdHVkZSBjb29yZGluYXRlIG9mIHRoZSBpbmNpZGVudCBsb2NhdGlvbi48L2xpPg0KICA8bGk+bGF0OiBSZXByZXNlbnRzIHRoZSBsYXRpdHVkZSBjb29yZGluYXRlIG9mIHRoZSBpbmNpZGVudCBsb2NhdGlvbi48L2xpPg0KPC91bD4NCg0KVGhpcyBkYXRhc2V0IHByb3ZpZGVzIHZhbHVhYmxlIGluc2lnaHRzIGludG8gdGhlIGRlbW9ncmFwaGljcyBvZiBpbmRpdmlkdWFscyBpbnZvbHZlZCBpbiB2YXJpb3VzIGluY2lkZW50cywgdGhlIG5hdHVyZSBhbmQgc2V2ZXJpdHkgb2YgdGhlIGluY2lkZW50cywgYW5kIHRoZWlyIHNwYXRpYWwgZGlzdHJpYnV0aW9uIGFjcm9zcyBkaWZmZXJlbnQgbmVpZ2hib3Job29kcyBhbmQgZGlzdHJpY3RzIHdpdGhpbiBQaGlsYWRlbHBoaWEuIEFuYWx5emluZyB0aGlzIGRhdGEgY2FuIGhlbHAgaWRlbnRpZnkgcGF0dGVybnMsIHRyZW5kcywgYW5kIGFyZWFzIG9mIGNvbmNlcm4gcmVsYXRlZCB0byBjcmltZSBhbmQgcHVibGljIHNhZmV0eSBpbiB0aGUgY2l0eS4NCldlJ3JlIG5hcnJvd2luZyBkb3duIG91ciBkYXRhc2V0IHRvIGZvY3VzIHNvbGVseSBvbiB0aGUgZGF0YSBmcm9tIDIwMjMuIFNpbmNlIHRoZXJlJ3Mgbm8gc3BlY2lmaWMgdmFyaWFibGUgZGVub3RpbmcgdGhlIHllYXIsIHdlJ2xsIGRlcml2ZSBpdCBmcm9tIHRoZSBleGlzdGluZyAnZGF0ZScgdmFyaWFibGUuIEFmdGVyIGNyZWF0aW5nIHRoZSAnWWVhcicgdmFyaWFibGUsIHdlIGNhbiB0aGVuIGZpbHRlciB0aGUgZGF0YSB0byBpbmNsdWRlIG9ubHkgb2JzZXJ2YXRpb25zIGZyb20gMjAyMy4gQ29uc2VxdWVudGx5LCBvdXIgdXBkYXRlZCBkYXRhc2V0IG5vdyBjb21wcmlzZXMgMTY2NiBvYnNlcnZhdGlvbnMgYW5kIDE5IHZhcmlhYmxlcywgaW5jbHVkaW5nIHRoZSBuZXdseSBhZGRlZCAnWWVhcicuDQpgYGB7ciwgY29tbWVudD1OQX0NCnBoaWxseSA8LSByZWFkLmNzdigiaHR0cHM6Ly9lY29sZW1hbjQ1MS5naXRodWIuaW8vd2Vic2l0ZS9EYXRhJTIwVmlzdWFsaXphdGlvbi9EYXRhc2V0cy9QaGlsbHlDcmltZVNpbmNlMjAxNS5jc3YiKQ0KDQojIENvbnZlcnQgZGF0ZSB2YXJpYWJsZSB0byBkYXRlIGZvcm1hdA0KcGhpbGx5JGRhdGUgPC0gYXMuRGF0ZShwaGlsbHkkZGF0ZSwgZm9ybWF0ID0gIiVtLyVkLyVZICVIOiVNIikNCg0KIyBFeHRyYWN0IHllYXIgZnJvbSBkYXRlIHZhcmlhYmxlDQpwaGlsbHkkeWVhciA8LSBmb3JtYXQocGhpbGx5JGRhdGUsICIlWSIpDQoNCnBoaWxseSA8LSBzdWJzZXQocGhpbGx5LCB5ZWFyPT0iMjAyMyIpDQpgYGANCg0KIyMgTGVhZmxldCBNYXANCiAgTm93LCBsZXQncyB2aXN1YWxpemUgZmF0YWwgdmVyc3VzIG5vbi1mYXRhbCBjcmltZXMgdGhhdCBvY2N1cnJlZCBpbiBQaGlsYWRlbHBoaWEgaW4gdGhlIHllYXIgMjAyMyBvbiBhIGxlYWZsZXQgbWFwLiBXZSdsbCBvbmNlIGFnYWluIHV0aWxpemUgdGhlICJjb2xvciIgZnVuY3Rpb24gdG8gZGlmZmVyZW50aWF0ZSBiZXR3ZWVuIHRoZSB0d28gdHlwZXMgb2YgY3JpbWVzLiBFYWNoIGNhdGVnb3J5LCAiRmF0YWwiIG9yICJOb25mYXRhbCwiIHdpbGwgYmUgYXNzaWduZWQgYSBkaXN0aW5jdCBjb2xvciwgcHJvdmlkaW5nIGEgdmlzdWFsIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjcmltZSB0eXBlLiBUaGUgbWFwIGZvbGxvd3MgYSBzaW1pbGFyIGZvcm1hdCB0byB0aGUgb25lcyBhYm92ZSwgd2l0aCBlYWNoIGNpcmNsZSBwb2ludCBkZW5vdGluZyBhIHNwZWNpZmljIGNyaW1lIGluY2lkZW50LiBIb3ZlcmluZyBvdmVyIGEgcG9pbnQgd2lsbCByZXZlYWwgZGV0YWlscyBzdWNoIGFzIHRoZSAiTmVpZ2hib3Job29kLCIgIkRhdGUsIiAiUmFjZSwiICJTZXgsIiAiQWdlLCIgYW5kICJTdHJlZXQiIGFzc29jaWF0ZWQgd2l0aCB0aGF0IHBhcnRpY3VsYXIgY3JpbWUuIFVwb24gdmlzdWFsIGluc3BlY3Rpb24gb2YgdGhlIG1hcCwgaXQgYXBwZWFycyB0aGF0IHRoZXJlIGlzIGEgbm90YWJsZSBkaXNwYXJpdHkgYmV0d2VlbiB0aGUgbnVtYmVyIG9mIG5vbi1mYXRhbCBjcmltZXMgYW5kIGZhdGFsIGNyaW1lcy4gSG93ZXZlciwgdG8gY29uZmlybSB0aGlzIG9ic2VydmF0aW9uLCBmdXJ0aGVyIGFuYWx5c2lzIHdvdWxkIGJlIG5lY2Vzc2FyeS4NCmBgYHtyLCBjb21tZW50PU5BfQ0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeShkcGx5cikNCiMgQ3JlYXRlIGNvbG9yIHBhbGV0dGUgZm9yIGZhdGFsIGFuZCBub24tZmF0YWwgY3JpbWVzDQpmYXRhbCA8LSAicmVkIg0Kbm9uX2ZhdGFsIDwtICJibHVlIg0KDQojIENyZWF0ZSBsZWFmbGV0IG1hcA0KbWFwIDwtIGxlYWZsZXQocGhpbGx5KSAlPiUNCiAgYWRkVGlsZXMoKSAlPiUNCiAgYWRkQ2lyY2xlTWFya2VycygNCiAgICB+bG5nLCB+bGF0LA0KICAgIGNvbG9yID0gaWZlbHNlKHBoaWxseSRmYXRhbCA9PSAiRmF0YWwiLCBmYXRhbCwgbm9uX2ZhdGFsKSwNCiAgICByYWRpdXMgPSA1LA0KICAgIGxhYmVsID0gfnBhc3RlKCJOZWlnaGJvcmhvb2Q6ICIsIG5laWdoYm9yaG9vZCwNCiAgICAgICAgICAgICAgICAgICAiRGF0ZTogIiwgZGF0ZSwNCiAgICAgICAgICAgICAgICAgICAiUmFjZTogIiwgcmFjZSwNCiAgICAgICAgICAgICAgICAgICAiU2V4OiAiLCBzZXgsDQogICAgICAgICAgICAgICAgICAgIkFnZTogIiwgYWdlLA0KICAgICAgICAgICAgICAgICAgICJTdHJlZXQ6ICIsIHN0cmVldF9uYW1lKSwNCiAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMoDQogICAgICBkaXJlY3Rpb24gPSAiYXV0byINCiAgICApDQogICkgJT4lDQogIGFkZExlZ2VuZCgNCiAgICBwb3NpdGlvbiA9ICJib3R0b21yaWdodCIsDQogICAgY29sb3JzID0gYyhmYXRhbCwgbm9uX2ZhdGFsKSwNCiAgICBsYWJlbHMgPSBjKCJGYXRhbCIsICJOb24tRmF0YWwiKSwNCiAgICB0aXRsZSA9ICJDcmltZSBUeXBlIg0KICApICU+JQ0KICBhZGRTY2FsZUJhcigpICU+JQ0KICBhZGRDb250cm9sKA0KICAgIGh0bWwgPSAiPGg0PlBoaWxhZGVscGhpYSBDcmltZSBMb2NhdGlvbnMgKDIwMTUtMjAyNCk8L2g0PiIsDQogICAgcG9zaXRpb24gPSAidG9wcmlnaHQiDQogICkNCg0KIyBEaXNwbGF5IHRoZSBtYXANCm1hcA0KYGBgDQoNCiMjIEJldHRlciBMZWFmbGV0IE1hcA0KICBOb3csIGxldCdzIGNyZWF0ZSBhbiBlbmhhbmNlZCBsZWFmbGV0IG1hcCB0byB2aXN1YWxpemUgZmF0YWwgdmVyc3VzIG5vbi1mYXRhbCBjcmltZXMgdGhhdCBvY2N1cnJlZCBpbiBQaGlsYWRlbHBoaWEuIFdlJ2xsIHV0aWxpemUgdGhlICJjb2xvciIgZnVuY3Rpb24gb25jZSBhZ2Fpbiwgd2l0aCBjb2xvcnMgcmVwcmVzZW50aW5nIHdoZXRoZXIgYSBjcmltZSB3YXMgbGFiZWxlZCBhcyAiRmF0YWwiIG9yICJOb25mYXRhbCIuIEVhY2ggY2F0ZWdvcnkgd2lsbCBiZSB1bmlxdWVseSBjb2xvcmVkLCBvZmZlcmluZyBjbGVhciB2aXN1YWwgaWRlbnRpZmljYXRpb24gb2YgdGhlIGNyaW1lIHR5cGUuIFdlJ2xsIHJlcHJlc2VudCBlYWNoIGNyaW1lIGxvY2F0aW9uIHdpdGggYSBjaXJjbGUgbWFya2VyIG9uIHRoZSBtYXAuIEhvdmVyaW5nIG92ZXIgYSBwb2ludCB3aWxsIGRpc3BsYXkgZGV0YWlsZWQgaW5mb3JtYXRpb24gaW5jbHVkaW5nICJPYmplY3QgSUQiLCAiWWVhciIsICJSYWNlIiwgIlNleCIsICJBZ2UiLCAiV291bmQiLCBhbmQgIkxvY2F0aW9uIiBmb3IgZWFjaCBjcmltZSBpbmNpZGVudC4NCmBgYHtyfQ0KIyBMb2FkIHJlcXVpcmVkIGxpYnJhcmllcw0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeShzZikNCg0KIyBTdXBwcmVzcyBtZXNzYWdlcyB3aGlsZSByZWFkaW5nIEdlb0pTT04gZmlsZXMNCm9wdGlvbnMod2Fybj0tMSkNCg0KIyBSZWFkIHRoZSBkYXRhIHdpdGhvdXQgcHJpbnRpbmcgbWVzc2FnZXMNCnBoaWxseSA8LSBzdF9yZWFkKCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9TVEE1NTNWSVovdzA4L1BoaWxseVNob290aW5ncy5nZW9qc29uIiwgcXVpZXQgPSBUUlVFKQ0KcGhpbGx5TmVpZ2hib3IgPC0gc3RfcmVhZCgiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vU1RBNTUzVklaL3cwOC9OZWlnaGJvcmhvb2RzX1BoaWxhZGVscGhpYS5nZW9qc29uIiwgcXVpZXQgPSBUUlVFKQ0KDQojIFJlc2V0IHdhcm5pbmcgc2V0dGluZ3MNCm9wdGlvbnMod2Fybj0wKQ0KDQojIENvbnZlcnQgJ3BoaWxseScgZGF0YSB0byBzZiBvYmplY3QNCnBoaWxseV9zZiA8LSBzdF9hc19zZihwaGlsbHksIGNvb3JkcyA9IGMoInBvaW50X3giLCAicG9pbnRfeSIpLCBjcnMgPSA0MzI2KQ0KDQojIERlZmluZSBjb2xvciBwYWxldHRlIGZvciBmYXRhbCBhbmQgbm9uLWZhdGFsIGNyaW1lcw0KZmF0YWxfY29sb3IgPC0gInJlZCINCm5vbl9mYXRhbF9jb2xvciA8LSAiZ29sZCINCg0KIyBDcmVhdGUgbGVhZmxldCBtYXANCm1hcCA8LSBsZWFmbGV0KCkgJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJEVzcmkuV29ybGRHcmF5Q2FudmFzKSAlPiUNCiAgYWRkUG9seWdvbnMoZGF0YSA9IHBoaWxseU5laWdoYm9yLA0KICAgICAgICAgICAgICBjb2xvciA9ICdza3libHVlJywNCiAgICAgICAgICAgICAgd2VpZ2h0ID0gMSkgICU+JQ0KICBhZGRDaXJjbGVNYXJrZXJzKGRhdGEgPSBwaGlsbHlfc2YsDQogICAgICAgICAgICAgICAgICAgfnBvaW50X3gsIH5wb2ludF95LA0KICAgICAgICAgICAgICAgICAgIGNvbG9yID0gaWZlbHNlKHBoaWxseSRmYXRhbCA9PSAxLCBmYXRhbF9jb2xvciwgbm9uX2ZhdGFsX2NvbG9yKSwNCiAgICAgICAgICAgICAgICAgICByYWRpdXMgPSA1LA0KICAgICAgICAgICAgICAgICAgIHBvcHVwID0gfnBhc3RlKCJPYmplY3QgSUQ6ICIsIG9iamVjdGlkLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8YnI+WWVhcjogIiwgeWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPGJyPlJhY2U6ICIsIHJhY2UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxicj5TZXg6ICIsIHNleCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPGJyPkFnZTogIiwgYWdlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8YnI+V291bmQ6ICIsIHdvdW5kLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8YnI+TG9jYXRpb246ICIsIGxvY2F0aW9uKSwNCiAgICAgICAgICAgICAgICAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMoDQogICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiYXV0byINCiAgICAgICAgICAgICAgICAgICApDQogICkgJT4lDQogIGFkZExlZ2VuZCgNCiAgICBwb3NpdGlvbiA9ICJib3R0b21yaWdodCIsDQogICAgY29sb3JzID0gYygicmVkIiwgImdvbGQiKSwNCiAgICBsYWJlbHMgPSBjKCJGYXRhbCIsICJOb24tRmF0YWwiKSwNCiAgICB0aXRsZSA9ICJDcmltZSBUeXBlIg0KICApICU+JQ0KICBhZGRTY2FsZUJhcigpICU+JQ0KICBhZGRDb250cm9sKA0KICAgIGh0bWwgPSAiPGg0PlBoaWxhZGVscGhpYSBDcmltZSBMb2NhdGlvbnMgKDIwMTUtMjAyNCk8L2g0PiIsDQogICAgcG9zaXRpb24gPSAidG9wcmlnaHQiDQogICkgJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJEVzcmkuV29ybGRHcmF5Q2FudmFzKSAlPiUNCiAgc2V0VmlldyhsbmcgPSAtNzUuMTUyNywgbGF0ID0gMzkuOTcwNywgem9vbSA9IDExKQ0KDQojIERpc3BsYXkgdGhlIG1hcA0KbWFwDQpgYGANCg0KXA0KDQpcDQoNCiMgVS5TLiBQcmVzaWRlbnRpYWwgRWxlY3Rpb24gRGF0YSAoMjAwMC0yMDI0KQ0KT3VyIGluaXRpYWwgZGF0YXNldCwgbmFtZWQgImVsZWN0aW9uIiwgZW5jb21wYXNzZXMgUHJlc2lkZW50aWFsIGVsZWN0aW9uIG91dGNvbWVzIHNwYW5uaW5nIHRoZSB5ZWFycyAyMDAwLCAyMDA0LCAyMDA4LCAyMDEyLCAyMDE2LCBhbmQgMjAyMC4gV2l0aCA3Miw2MTcgb2JzZXJ2YXRpb25zIGFuZCAxMiB2YXJpYWJsZXMsIGl0IHByb3ZpZGVzIGNvbXByZWhlbnNpdmUgaW5zaWdodHMgaW50byBlYWNoIHN0YXRlJ3MgYW5kIGNvdW50eSdzIGVsZWN0aW9uIHJlc3VsdHMsIGRldGFpbGluZyB0aGUgd2lubmluZyBjYW5kaWRhdGUgaW4gZWFjaCBjb3VudHksIGFsb25nIHdpdGggdGhlIHRvdGFsIHZvdGVzIHJlY2VpdmVkIGJ5IGVhY2ggY2FuZGlkYXRlLg0KDQpQcmlvciB0byBhbmFseXNpcywgc29tZSBkYXRhIGNsZWFuaW5nIHdhcyBpbXBlcmF0aXZlLCBwYXJ0aWN1bGFybHkgY29uY2VybmluZyB0aGUgY291bnR5IEZJUFMgY29kZXPigJRhIHVuaXF1ZSA1LWRpZ2l0IGlkZW50aWZpZXIgYXNzaWduZWQgdG8gZXZlcnkgY291bnR5IGluIHRoZSBVbml0ZWQgU3RhdGVzLiBJbml0aWFsbHksIGNlcnRhaW4gY29kZXMgZXJyb25lb3VzbHkgY29udGFpbmVkIG9ubHkgNCBkaWdpdHMsIG5vdGFibHkgd2hlbiBhICIwIiBwcmVjZWRlZCB0aGUgZmlyc3QgZGlnaXQuIEZvciBpbnN0YW5jZSwgQXV0YXVnYSBDb3VudHksIEFsYWJhbWEncyBGSVBTIGNvZGUgIjAxMDAxIiB3YXMgcmVjb3JkZWQgYXMgIjEwMDEiIGluIHRoZSBkYXRhc2V0LiBUaGlzIGRpc2NyZXBhbmN5IHdhcyByZWN0aWZpZWQgdXNpbmcgdGhlICJURVhUIiBmdW5jdGlvbiBpbiBFeGNlbCwgYXBwbGllZCBiZWZvcmUgaW1wb3J0aW5nIHRoZSBkYXRhIGludG8gdGhlICJlbGVjdGlvbiIgc2V0Lg0KDQpVdGlsaXppbmcgdGhlICJlbGVjdGlvbiIgZGF0YXNldCwgb3VyIG9iamVjdGl2ZSBpcyB0byBzcGxpdCB0aGUgZGF0YSBpbnRvIGNvdW50eS1sZXZlbCBhbmQgc3RhdGUtbGV2ZWwgc3Vic2V0cy4gQm90aCBzdWJzZXRzIGluY2x1ZGUgYSBuZXcgdmFyaWFibGUgbmFtZWQgInBhcnR5X3BlcmNlbnRhZ2UsIiBjYWxjdWxhdGVkIHRvIGFzY2VydGFpbiB0aGUgcGVyY2VudGFnZSBvZiB2b3RlcnMgZmF2b3JpbmcgdGhlIHdpbm5pbmcgcGFydHkgd2l0aGluIHRoZWlyIHJlc3BlY3RpdmUgc3RhdGUgb3IgY291bnR5LiBUaGUgImNvdW50eV9kYXRhIiBzdWJzZXQgcHJvdmlkZXMgZWxlY3Rpb24gcmVzdWx0cyBjYXRlZ29yaXplZCBieSBjb3VudHksIHdoaWxlIHRoZSAic3RhdGVfZGF0YSIgc3Vic2V0IHByZXNlbnRzIGVsZWN0aW9uIG91dGNvbWVzIGFnZ3JlZ2F0ZWQgYnkgc3RhdGUuIEZ1cnRoZXJtb3JlLCBib3RoIHN1YnNldHMgcmV0YWluIHNvbGVseSB0aGUgd2lubmluZyBwYXJ0eSdzIGluZm9ybWF0aW9uIGZvciBhbmFseXNpcy4NCmBgYHtyfQ0KIyBMb2FkIHRoZSByZXF1aXJlZCBsaWJyYXJ5DQpsaWJyYXJ5KGRwbHlyKQ0KDQojIFJlYWQgdGhlIGRhdGENCmVsZWN0aW9uIDwtIHJlYWQuY3N2KCJodHRwczovL2Vjb2xlbWFuNDUxLmdpdGh1Yi5pby93ZWJzaXRlL0RhdGElMjBWaXN1YWxpemF0aW9uL0RhdGFzZXRzL1ByZXNpZGVudGlhbEVsZWN0aW9uMjAwMFRvMjAyMC5jc3YiKQ0KDQojIENvdW50eS1sZXZlbCBEYXRhDQpjb3VudHlfZGF0YSA8LSBlbGVjdGlvbiAlPiUNCiAgZ3JvdXBfYnkoeWVhciwgc3RhdGUsIGNvdW50eV9uYW1lKSAlPiUNCiAgbXV0YXRlKHBhcnR5X3BlcmNlbnRhZ2UgPSBjYW5kaWRhdGV2b3RlcyAvIHN1bShjYW5kaWRhdGV2b3RlcykgKiAxMDApICU+JQ0KICBmaWx0ZXIocGFydHlfcGVyY2VudGFnZSA9PSBtYXgocGFydHlfcGVyY2VudGFnZSkpICU+JQ0KICBzZWxlY3QoeWVhciwgc3RhdGUsIGNvdW50eV9maXBzLCBwYXJ0eSwgY2FuZGlkYXRlLCBjYW5kaWRhdGV2b3RlcywgcGFydHlfcGVyY2VudGFnZSkNCg0KIyBTdGF0ZS1sZXZlbCBEYXRhDQpzdGF0ZV9kYXRhIDwtIGVsZWN0aW9uICU+JQ0KICBncm91cF9ieSh5ZWFyLCBzdGF0ZSkgJT4lDQogIG11dGF0ZShwYXJ0eV9wZXJjZW50YWdlID0gY2FuZGlkYXRldm90ZXMgLyBzdW0oY2FuZGlkYXRldm90ZXMpICogMTAwKSAlPiUNCiAgZmlsdGVyKHBhcnR5X3BlcmNlbnRhZ2UgPT0gbWF4KHBhcnR5X3BlcmNlbnRhZ2UpKSAlPiUNCiAgc2VsZWN0KHllYXIsIHN0YXRlLCBwYXJ0eSwgY2FuZGlkYXRlLCBjYW5kaWRhdGV2b3RlcywgcGFydHlfcGVyY2VudGFnZSkNCg0KIyBTYXZlIGNvdW50eS1sZXZlbCBkYXRhIHRvIGEgbmV3IENTViBmaWxlDQp3cml0ZS5jc3YoY291bnR5X2RhdGEsIGZpbGUgPSAiY291bnR5X2xldmVsX2RhdGEuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQoNCiMgU2F2ZSBzdGF0ZS1sZXZlbCBkYXRhIHRvIGEgbmV3IENTViBmaWxlDQp3cml0ZS5jc3Yoc3RhdGVfZGF0YSwgZmlsZSA9ICJzdGF0ZV9sZXZlbF9kYXRhLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KYGBgDQoNCiMjIENob3JvcGxldGggTWFwDQogIE5vdyB0aGF0IHdlJ3ZlIHNwbGl0IHRoZSBkYXRhc2V0IGludG8gImNvdW50eV9kYXRhLCIgZm9jdXNpbmcgc29sZWx5IG9uIGVsZWN0aW9uIHJlc3VsdHMgKHNwZWNpZmljYWxseSB0aGUgd2lubmluZyBwYXJ0eSkgYXQgdGhlIGNvdW50eSBsZXZlbCwgd2UgY2FuIGxldmVyYWdlIFRhYmxlYXUsIGFuIGludGVyYWN0aXZlIGRhdGEgdmlzdWFsaXphdGlvbiB0b29sLCB0byBjcmFmdCBhIENob3JvcGxldGggTWFwLiBUaGlzIG1hcCB3aWxsIGRpc3BsYXkgcHJlc2lkZW50aWFsIGVsZWN0aW9uIG91dGNvbWVzIGF0IHRoZSBjb3VudHkgbGV2ZWwuIERpZmZlcmVudCBjb2xvcnMgYXJlIGFzc2lnbmVkIHRvIHJlcHJlc2VudCB0aGUgbWFqb3IgcG9saXRpY2FsIHBhcnRpZXMgKERlbW9jcmF0ICYgUmVwdWJsaWNhbiksIGFuZCBlYWNoIGNvdW50eSdzIHNoYWRpbmcgcmVmbGVjdHMgdGhlIHdpbm5pbmcgcG9saXRpY2FsIHBhcnR5IGluIGEgc3BlY2lmaWMgZWxlY3Rpb24geWVhci4gVGhlIGludGVyYWN0aXZlIG1hcCBpbmNsdWRlcyBhIGZpbHRlciB0byBhbHRlciB0aGUgZGlzcGxheWVkIHllYXIocykuIEFkZGl0aW9uYWxseSwgaG92ZXIgdGV4dCBhcHBlYXJzIHdoZW4gaG92ZXJpbmcgb3ZlciBhIHNwZWNpZmljIGNvdW50eSBvbiB0aGUgbWFwLCBwcm92aWRpbmcgaW5mb3JtYXRpb24gc3VjaCBhcyAieWVhciwiICJzdGF0ZSwiICJwYXJ0eSwiICJjYW5kaWRhdGV2b3RlcywiIGFuZCAicGFydHlfcGVyY2VudGFnZSIgZm9yIHRoZSByZXNwZWN0aXZlIGNvdW50eS4NClwNCjx0YWJsZSBib3JkZXIgPSAwIGJvcmRlcmNvbG9yPSJkYXJrZ3JlZW4iIGJnY29sb3I9JyNmNmY2ZjYnICB3aWR0aD0xMDAlICBhbGlnbiA9IGNlbnRlcj4NCjx0cj4NCjx0ZD4NCjxkaXYgY2xhc3M9J3RhYmxlYXVQbGFjZWhvbGRlcicgaWQ9J3ZpejE3MTIyNjkyOTQwMjAnIHN0eWxlPSdwb3NpdGlvbjogcmVsYXRpdmUnPjxub3NjcmlwdD48YSBocmVmPScjJz48aW1nIGFsdD0nQ2hvcm9wbGV0aCBNYXAgJyBzcmM9J2h0dHBzOiYjNDc7JiM0NztwdWJsaWMudGFibGVhdS5jb20mIzQ3O3N0YXRpYyYjNDc7aW1hZ2VzJiM0NztDaCYjNDc7Q2hvcm9wbGV0aF9NYXBfRmluYWwmIzQ3O1NoZWV0MSYjNDc7MV9yc3MucG5nJyBzdHlsZT0nYm9yZGVyOiBub25lJyAvPjwvYT48L25vc2NyaXB0PjxvYmplY3QgY2xhc3M9J3RhYmxlYXVWaXonICBzdHlsZT0nZGlzcGxheTpub25lOyc+PHBhcmFtIG5hbWU9J2hvc3RfdXJsJyB2YWx1ZT0naHR0cHMlM0ElMkYlMkZwdWJsaWMudGFibGVhdS5jb20lMkYnIC8+IDxwYXJhbSBuYW1lPSdlbWJlZF9jb2RlX3ZlcnNpb24nIHZhbHVlPSczJyAvPiA8cGFyYW0gbmFtZT0nc2l0ZV9yb290JyB2YWx1ZT0nJyAvPjxwYXJhbSBuYW1lPSduYW1lJyB2YWx1ZT0nQ2hvcm9wbGV0aF9NYXBfRmluYWwmIzQ3O1NoZWV0MScgLz48cGFyYW0gbmFtZT0ndGFicycgdmFsdWU9J25vJyAvPjxwYXJhbSBuYW1lPSd0b29sYmFyJyB2YWx1ZT0neWVzJyAvPjxwYXJhbSBuYW1lPSdzdGF0aWNfaW1hZ2UnIHZhbHVlPSdodHRwczomIzQ3OyYjNDc7cHVibGljLnRhYmxlYXUuY29tJiM0NztzdGF0aWMmIzQ3O2ltYWdlcyYjNDc7Q2gmIzQ3O0Nob3JvcGxldGhfTWFwX0ZpbmFsJiM0NztTaGVldDEmIzQ3OzEucG5nJyAvPiA8cGFyYW0gbmFtZT0nYW5pbWF0ZV90cmFuc2l0aW9uJyB2YWx1ZT0neWVzJyAvPjxwYXJhbSBuYW1lPSdkaXNwbGF5X3N0YXRpY19pbWFnZScgdmFsdWU9J3llcycgLz48cGFyYW0gbmFtZT0nZGlzcGxheV9zcGlubmVyJyB2YWx1ZT0neWVzJyAvPjxwYXJhbSBuYW1lPSdkaXNwbGF5X292ZXJsYXknIHZhbHVlPSd5ZXMnIC8+PHBhcmFtIG5hbWU9J2Rpc3BsYXlfY291bnQnIHZhbHVlPSd5ZXMnIC8+PHBhcmFtIG5hbWU9J2xhbmd1YWdlJyB2YWx1ZT0nZW4tVVMnIC8+PHBhcmFtIG5hbWU9J2ZpbHRlcicgdmFsdWU9J3B1Ymxpc2g9eWVzJyAvPjwvb2JqZWN0PjwvZGl2PiAgICAgICAgICAgICAgICANCjxzY3JpcHQgdHlwZT0ndGV4dC9qYXZhc2NyaXB0Jz4gICAgICAgICAgICAgICAgICAgIHZhciBkaXZFbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3ZpejE3MTIyNjkyOTQwMjAnKTsgICAgICAgICAgICAgICAgICAgIHZhciB2aXpFbGVtZW50ID0gZGl2RWxlbWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnb2JqZWN0JylbMF07ICAgICAgICAgICAgICAgICAgICB2aXpFbGVtZW50LnN0eWxlLndpZHRoPScxMDAlJzt2aXpFbGVtZW50LnN0eWxlLmhlaWdodD0oZGl2RWxlbWVudC5vZmZzZXRXaWR0aCowLjc1KSsncHgnOyAgICAgICAgICAgICAgICAgICAgdmFyIHNjcmlwdEVsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTsgICAgICAgICAgICAgICAgICAgIHNjcmlwdEVsZW1lbnQuc3JjID0gJ2h0dHBzOi8vcHVibGljLnRhYmxlYXUuY29tL2phdmFzY3JpcHRzL2FwaS92aXpfdjEuanMnOyAgICAgICAgICAgICAgICAgICAgdml6RWxlbWVudC5wYXJlbnROb2RlLmluc2VydEJlZm9yZShzY3JpcHRFbGVtZW50LCB2aXpFbGVtZW50KTsgICAgICAgICAgICAgICAgDQo8L3NjcmlwdD4NCjwvdGQ+DQo8L3RyPg0KPC90YWJsZT4gICAgICAgICAgICANClw=